import * as vscode from 'vscode';
import { StorageService } from './storage-service';

/**
 * openWeb 认证服务
 * 负责与独立的 openWeb 网站通信，获取和管理用户 token
 */

export interface OpenWebUserInfo {
  userId: string;
  userName: string;
  userEmail: string;
  avatarUrl?: string;
}

export interface OpenWebAuthData {
  token: string;
  refreshToken: string;
  expiresAt: number;
  userInfo: OpenWebUserInfo;
  lastVerified?: number;
}

export interface OpenWebAuthState {
  isAuthenticated: boolean;
  authData?: OpenWebAuthData;
}

export type OpenWebAuthStateChangeCallback = (
  authState: OpenWebAuthState,
) => void | Promise<void>;

export class OpenWebAuthService {
  private static instance: OpenWebAuthService;
  private storageService = StorageService.getInstance();
  private readonly AUTH_STATE_KEY = 'stagewise.openweb.authState';
  private readonly OPENWEB_URL = 'http://localhost:5175'; // openWeb 运行的地址
  private authStateChangeCallbacks: OpenWebAuthStateChangeCallback[] = [];
  private outputChannel: vscode.OutputChannel;

  // 用于等待认证回调的 Promise
  private authCallbackPromise: {
    resolve: (data: OpenWebAuthData) => void;
    reject: (error: Error) => void;
  } | null = null;

  private constructor() {
    this.outputChannel = vscode.window.createOutputChannel(
      'stagewise - openWeb Auth',
    );
  }

  public static getInstance(): OpenWebAuthService {
    if (!OpenWebAuthService.instance) {
      OpenWebAuthService.instance = new OpenWebAuthService();
    }
    return OpenWebAuthService.instance;
  }

  /**
   * 处理来自 openWeb 的认证回调
   */
  public async handleAuthCallback(uri: vscode.Uri): Promise<void> {
    try {
      this.log('========== 收到认证回调 ==========');
      this.log('完整 URI:', uri.toString());
      this.log('URI path:', uri.path);
      this.log('URI query:', uri.query);

      // 从 URL 参数中提取认证信息
      const params = new URLSearchParams(uri.query);
      const token = params.get('token');
      const refreshToken = params.get('refreshToken');
      const expiresAt = params.get('expiresAt');
      const userId = params.get('userId');
      const userName = params.get('userName');
      const userEmail = params.get('userEmail');
      const avatarUrl = params.get('avatarUrl');

      this.log('提取的参数:');
      this.log('  token:', token);
      this.log('  refreshToken:', refreshToken);
      this.log('  expiresAt:', expiresAt);
      this.log('  userId:', userId);
      this.log('  userName:', userName);
      this.log('  userEmail:', userEmail);
      this.log('  avatarUrl:', avatarUrl);

      // 验证必需参数
      if (
        !token ||
        !refreshToken ||
        !expiresAt ||
        !userId ||
        !userName ||
        !userEmail
      ) {
        const missing = [];
        if (!token) missing.push('token');
        if (!refreshToken) missing.push('refreshToken');
        if (!expiresAt) missing.push('expiresAt');
        if (!userId) missing.push('userId');
        if (!userName) missing.push('userName');
        if (!userEmail) missing.push('userEmail');
        const error = new Error(`缺少必需的认证参数: ${missing.join(', ')}`);

        // 如果有等待中的 Promise，拒绝它
        if (this.authCallbackPromise) {
          this.authCallbackPromise.reject(error);
          this.authCallbackPromise = null;
        }

        throw error;
      }

      // 构建认证数据
      const authData: OpenWebAuthData = {
        token,
        refreshToken,
        expiresAt: Number.parseInt(expiresAt, 10),
        userInfo: {
          userId,
          userName,
          userEmail,
          avatarUrl: avatarUrl || undefined,
        },
        lastVerified: Date.now(),
      };

      this.log('构建的认证数据:', JSON.stringify(authData, null, 2));

      // 保存认证状态
      await this.saveAuthData(authData);

      // 通知状态变化
      await this.notifyAuthStateChange({
        isAuthenticated: true,
        authData,
      });

      this.log('✅ 认证成功！用户:', userName, '邮箱:', userEmail);
      this.log('========================================');

      // 如果有等待中的 Promise，resolve 它
      if (this.authCallbackPromise) {
        this.authCallbackPromise.resolve(authData);
        this.authCallbackPromise = null;
      }

      // 静默认证，不显示弹窗
    } catch (error) {
      this.log('❌ 认证失败:', error);

      // 如果有等待中的 Promise，拒绝它
      if (this.authCallbackPromise) {
        this.authCallbackPromise.reject(
          error instanceof Error ? error : new Error(String(error)),
        );
        this.authCallbackPromise = null;
      }

      await vscode.window.showErrorMessage(
        `认证失败: ${error instanceof Error ? error.message : '未知错误'}`,
      );
    }
  }

  /**
   * 检查是否已经有 token（不检查过期，因为我们不在意过期问题）
   */
  public async hasValidToken(): Promise<boolean> {
    const authData = await this.getAuthData();

    if (!authData) {
      this.log('没有找到认证数据');
      return false;
    }

    // 简化：不检查过期，只要有 token 就认为有效
    this.log('已有 token:', authData.userInfo.userName);
    return true;
  }

  /**
   * 尝试获取 token，如果没有则自动静默打开 openWeb 网站
   * 用户无感知，自动完成认证流程
   * @param timeoutMs 等待认证回调的超时时间（毫秒），默认 2 分钟
   */
  public async ensureAuthenticated(
    timeoutMs = 120000,
  ): Promise<OpenWebAuthData | null> {
    // 先检查本地是否有有效 token
    const hasToken = await this.hasValidToken();

    if (hasToken) {
      const authData = await this.getAuthData();
      this.log('使用现有 token');
      return authData;
    }

    // 没有有效 token，静默打开 openWeb 网站（无弹窗）
    this.log('需要认证，自动打开 openWeb（静默）');
    this.log(`等待用户完成认证（超时: ${timeoutMs / 1000}秒）...`);

    try {
      // 创建一个 Promise 等待认证回调
      const authPromise = new Promise<OpenWebAuthData>((resolve, reject) => {
        this.authCallbackPromise = { resolve, reject };
      });

      // 创建超时 Promise
      const timeoutPromise = new Promise<never>((_, reject) => {
        setTimeout(() => {
          reject(new Error('认证超时：用户未在规定时间内完成认证'));
        }, timeoutMs);
      });

      // 打开认证网站
      await this.openAuthWebsiteSilent();

      // 等待认证完成或超时
      const authData = await Promise.race([authPromise, timeoutPromise]);

      this.log('✅ 认证流程完成');
      return authData;
    } catch (error) {
      this.log('❌ 认证流程失败:', error);
      // 清理 Promise
      this.authCallbackPromise = null;

      // 超时不算错误，只是返回 null
      if (error instanceof Error && error.message.includes('认证超时')) {
        this.log('用户未完成认证，继续使用离线模式');
        return null;
      }

      throw error;
    }
  }

  /**
   * 静默打开 openWeb 认证网站（无提示信息）
   * 用于自动化流程，用户无感知
   */
  private async openAuthWebsiteSilent(): Promise<void> {
    try {
      const authUrl = `${this.OPENWEB_URL}?source=vscode`;
      this.log('静默打开认证网站:', authUrl);
      await vscode.env.openExternal(vscode.Uri.parse(authUrl));
    } catch (error) {
      this.log('打开认证网站失败:', error);
      throw error;
    }
  }

  /**
   * 登出（清除本地 token）
   */
  public async logout(): Promise<void> {
    await this.storageService.delete(this.AUTH_STATE_KEY);

    await this.notifyAuthStateChange({
      isAuthenticated: false,
    });

    this.log('已登出');
  }

  /**
   * 获取认证数据
   */
  public async getAuthData(): Promise<OpenWebAuthData | null> {
    const state = await this.storageService.get<OpenWebAuthState>(
      this.AUTH_STATE_KEY,
    );
    return state?.authData || null;
  }

  /**
   * 获取用户信息
   */
  public async getUserInfo(): Promise<OpenWebUserInfo | null> {
    const authData = await this.getAuthData();
    return authData?.userInfo || null;
  }

  /**
   * 同步获取用户信息（从缓存）
   * 注意：首次调用可能返回 null，建议先调用 ensureAuthenticated()
   */
  public getUserInfoSync(): OpenWebUserInfo | null {
    // 从 storageService 的内存缓存中同步获取
    const state = this.storageService.getSync<OpenWebAuthState>(
      this.AUTH_STATE_KEY,
    );
    return state?.authData?.userInfo || null;
  }

  /**
   * 获取 token（简化：不检查过期）
   */
  public async getToken(): Promise<string | null> {
    const authData = await this.getAuthData();

    if (!authData) {
      return null;
    }

    // 简化：不检查过期，直接返回 token
    return authData.token;
  }

  /**
   * 获取认证状态（简化：不检查过期）
   */
  public async getAuthState(): Promise<OpenWebAuthState> {
    const authData = await this.getAuthData();

    if (!authData) {
      return { isAuthenticated: false };
    }

    // 简化：不检查过期，只要有数据就认为已认证
    return {
      isAuthenticated: true,
      authData,
    };
  }

  /**
   * 保存认证数据
   */
  private async saveAuthData(authData: OpenWebAuthData): Promise<void> {
    const authState: OpenWebAuthState = {
      isAuthenticated: true,
      authData,
    };

    await this.storageService.set(this.AUTH_STATE_KEY, authState);
    this.log('认证数据已保存');
  }

  /**
   * 注册认证状态变化回调
   */
  public onAuthStateChanged(
    callback: OpenWebAuthStateChangeCallback,
  ): () => void {
    this.authStateChangeCallbacks.push(callback);

    // 返回取消订阅函数
    return () => {
      const index = this.authStateChangeCallbacks.indexOf(callback);
      if (index > -1) {
        this.authStateChangeCallbacks.splice(index, 1);
      }
    };
  }

  /**
   * 通知所有回调
   */
  private async notifyAuthStateChange(
    authState: OpenWebAuthState,
  ): Promise<void> {
    for (const callback of this.authStateChangeCallbacks) {
      try {
        await callback(authState);
      } catch (error) {
        this.log('回调执行失败:', error);
      }
    }
  }

  /**
   * 日志输出
   */
  private log(...args: any[]): void {
    const message = args
      .map((arg) =>
        typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg),
      )
      .join(' ');
    this.outputChannel.appendLine(`[${new Date().toISOString()}] ${message}`);
    console.log('[OpenWebAuthService]', ...args);
  }

  /**
   * 显示日志输出
   */
  public showOutput(): void {
    this.outputChannel.show();
  }

  /**
   * 设置 openWeb URL（用于配置不同的环境）
   */
  public setOpenWebUrl(url: string): void {
    (this as any).OPENWEB_URL = url;
    this.log('openWeb URL 已更新:', url);
  }
}
